/********************************************************************
 Andras Veres 
 *******************************************************************/

#include <p24FJ64GB002.h>

#include "system.h"
#include "system_config.h"

#include <xc.h>
//#include <p24Fxxxx.h>


#include <libpic30.h>


#include <dpslp.h>
#include <Rtcc.h>
#include <stdio.h>

#include "usb/usb.h"
#include "usb/usb_device_hid.h"

#include "app_device_custom_hid.h"

#include <spi.h>
#include "adc.h"
#include "leds.h"


#define BLINK_START     1

LED blink_leds[10];
int blink_times[10]; // must sum to 4096
volatile int blink_len=0;
volatile int blink_start = 0;


volatile char rtcintflag = 0;
volatile char t1intflag = 0;


int usb_on = 0;
CONTEXT read_state;

void __attribute__((interrupt,auto_psv)) _T1Interrupt(void)
{
   IFS0bits.T1IF = 0; //Reset Timer1 interrupt flag

   if(blink_len>0) {
      LED led = blink_leds[blink_len-1];
      int time = blink_times[blink_len-1];

      LED_Off(RED);
      LED_Off(GREEN);

      PR1 = time;
      LED_On(led);

      blink_len --;

      if(blink_start) {
         t1intflag++;
         blink_start = 0;
      }

      return;
   }
   
   PR1 = 32768 / DT;
   ts += 1000 / DT;

   t1intflag++;
}


void __attribute__((interrupt,auto_psv)) _RTCCInterrupt(void)
 {
     IFS3bits.RTCIF = 0;

     ALCFGRPTbits.ALRMEN = 1;   // enable alarm (needs to be reset after alarm)
     RCFGCALbits.RTCEN = 1;

     rtcintflag=1;
 }

void __attribute__ ((interrupt, no_auto_psv)) _U2RXInterrupt(void) {
	IFS1bits.U2RXIF = 0;
}
void __attribute__ ((interrupt, no_auto_psv)) _U2TXInterrupt(void) {
	IFS1bits.U2TXIF = 0;
}

void SetBlinkBoth() {
    // on for approx 9ms RED then 9ms GREEN

    blink_leds[2] = RED;
    blink_times[2] = 300;

    blink_leds[1] = GREEN;
    blink_times[1] = 300;

    blink_leds[0] = LED_NONE;
    blink_times[0] = 4096-600;
    blink_len=3;
    blink_start = 1;
}

void SetBlink(LED led) {
    // on for approx 9ms

    blink_leds[1] = led;
    blink_times[1] = 300;

    blink_leds[0] = LED_NONE;
    blink_times[0] = 4096-300;
    blink_len=2;
    blink_start = 1;
}


SRC ptr;

// ===========================================================================
// ========================================= MAIN ============================
// ===========================================================================

MAIN_RETURN main(void)
{

    U1CONbits.USBEN = 0;    // These can have an effect on the port settings, so we have to do the USB stuff before port init
    U1PWRCbits.USBPWR = 0;
    usb_on = 0;
    ts = 0;

    InitPorts(); // Set TRIS and set all CS, power etc to off state
    
    // TEST
    OSCCONbits.POSCEN = 0; // Primary oscillator disabled during Sleep mode

    SlowClock();
    InitUART2(9600, 2000000);
    //InitSPI(7,3);
    InitSPI(7,3);

    InitT1();


    /*

    OSCCONbits.SOSCEN = 1;      // enable 32khz oscillator
    NVMKEY = 0x55;              // 55/AA sequence to enable write to RTCWREN
    NVMKEY = 0xAA;
    RCFGCALbits.RTCWREN = 1;    // enable write to RTC register
    RCFGCALbits.RTCEN = 1;      // RTC module enabled
    //PADCFG1bits.RTSECSEL = 1;   // RTC clock output pin outputs clock (and not alarm)
    //PADCFG1bits.RTSECSEL = 0;   // RTC clock output pin outputs alarm (and not clock)
    RCFGCALbits.RTCOE = 0;      // RTC clock output pin disable

    // ALARM
    ALCFGRPTbits.ALRMEN = 1;   // enable alarm (needs to be reset after alarm)
    ALCFGRPTbits.CHIME = 0;    // chime indefinitly
    ALCFGRPTbits.AMASK = 0;    // every half second
    RCFGCALbits.RTCWREN = 1;   // enable write to RTC register
    IPC15bits.RTCIP = 7;       // RTC pririty set to 7
    IEC3bits.RTCIE = 1;        // RTC interrupt enabled
*/
    
    cacheptr = 0;
    pageptr = 0;
    int n_flash = 0;

    bool ds = IsResetFromDeepSleep();

    if(ds==FALSE) {
       log("\n\rBoot normal");

       RtccInitClock();
       
       // Set RTCC to some initial value
       NVMKEY = 0x55;              // 55/AA sequence to enable write to RTCWREN
       NVMKEY = 0xAA;
       RCFGCALbits.RTCWREN = 1;
       RCFGCALbits.RTCPTR = 3;         // RTCC Value Register Window Pointer bits
       RTCVAL = 0x0010;                     // Set Year (#0x00YY)
       RTCVAL = 0x0101;// Set Month and Day (#0xMMDD)
       RTCVAL = 0x0101;   // Set Weekday and Hour (#0x0WHH). Weekday from 0 to 6
       RTCVAL = 0x0101;  // Set Minute and Second (#0xMMSS)

    }

    if(ds==TRUE) {

       ReadDSGPR( &read_state);	//Read the deep sleep GPR
       DeepSleepWakeUpSource(&ptr);	//Check the deep sleep wakup soruce (if required)
       ReleaseDeepSleep();		//Release the Deep sleep (IO configuration)

       log("\n\rBoot DS");

    }

    PowerOpamp(true);

    SetRTC();

    //printtime();
    
    //ALCFGRPTbits.ALRMEN = 1;   // enable alarm (needs to be reset after alarm)
    //ALCFGRPTbits.CHIME = 0;    // chime indefinitly
    //ALCFGRPTbits.AMASK = 0b0010;    // every half second
    //RCFGCALbits.RTCWREN = 1;   // enable write to RTC register
    //IPC15bits.RTCIP = 7;       // RTC pririty set to 7
    //IEC3bits.RTCIE = 1;        // RTC interrupt enabled
    
    //SlowClock();
    //InitUART2(9600, 2000000);

    /*
    log("fcy:%lu", (unsigned long) ((100)*(fcy)/1000000ULL));
    unsigned long y = 2000000;
    while(1) {
         //__delay32(200);
         LED_On(RED);
         //    unsigned long x = y/10000;

         //__delay32(x);
         LED_Off(RED);
    }
*/

   /*
    while(1) {
        LED_On(RED);
writepage(pageptr);
LED_Off(RED);
       __delay_ms(5000);
    }
*/
    
    int res = triggeradc();
    if(res ==0) {
        log("Unexpected, retrigger");
        res = triggeradc();
        if(res == 0) log("RetrX failed");
    } else log("Initial trigger OK");

    if(ds)SetBlink(GREEN);
    else SetBlink(RED);
    while(blink_len) Sleep();


    rtcintflag = 0;
    t1intflag = 0;

    if(ds==FALSE) {
       PowerOpamp(false);
       SetRTC();

           // code taken from the pic datasheet, need to disable interrupts
           log("Deep");
           asm("disi #4");
           asm("bset DSCON, #15");
           asm("nop");
           asm("nop");
           asm("nop");
           asm("pwrsav #0");

       log("First Deep");
       GotoDeepSleep();
       log("WTF");
    }

    if(waitbusy()) log("BUSY");
    clearblockprotection();
    
    //------------------------------------------
    while(1) {
        int r = 0;

        if(t1intflag == 0 && usb_on == 0) {
            //log("Sleep");
            Sleep();
        }

        if(usb_on) USBStuff();

        if(!USB_BUS_SENSE) {
            if(usb_on==1) {
               log("USB OFF");
               USBOff();
               usb_on = 0;
               Sleep();

               SlowClock();
               InitUART2(9600, 2000000);
            }
        } else {
           // if we just detected usb
           if(usb_on == 0) {
              FastClock();
              InitUART2(9600, 16000000);
              InitSPI(2,2);

              log("USB ON");
              USBOn();
              usb_on = 1;
           }
        }

        if(!t1intflag) continue;

        //------------------------------ timer triggered
        t1intflag=0;

        if(t1intflag>1) log("*");


        n_flash++;

        // Flash every 5 sec 
        if(n_flash>=8*5) {
           SetBlink(RED);
           //log("F%i", n_flash);
           n_flash = 0;
        }

        if(t1intflag>1) log(":");

        r = getadc();
        if(r==0) {
            log("ADCERR");
        } else log("G%lu", hres);

        // if no gsr read, or we just booted up, let's wait
        // for an rtcc interrupt 
        if((usb_on==0) && (hres>4000000 || hres < 100)) {
           PowerOpamp(false);

           SetRTC();
           SetRTC();

           LED_Off(GREEN);
           LED_Off(RED);

           // code taken from the pic datasheet, need to disable interrupts
           log("Deep");
           asm("disi #4");
           asm("bset DSCON, #15");
           asm("nop");
           asm("nop");
           asm("nop");
           asm("pwrsav #0");

           log("Deep2");
           GotoDeepSleep();
           {
               int i = DSCONbits.DSEN;
              log("DS failed %i", i);
           }
        }

        r = triggeradc();
        if(res ==0) {
           log("Unexpected, retrigger");
           res = triggeradc();
           if(res == 0) log("Retr failed");
        }

        if(t1intflag) log("?");

        // write gsr data to flash
        memcpy(pcache+cacheptr, &hres, 4);
        cacheptr += 4;

        if(pageptr==0) {
           // finding memory takes approx 2.2ms
           pageptr = findmem();
           log("P%lu", pageptr);
        }

        if(cacheptr==256) {
           cacheptr = 0;

           log("W%lu", pageptr)

           // flash write comes here... (takes approx 4.3ms)
           if(waitbusy()) log("B");
           writeenable();
           writepage(pageptr);

           pageptr += 256;
        }

        if(cacheptr == 0) {
           GetTimeStamp();
           memcpy(pcache, timestamp, 8);
           cacheptr = 8;
        }

        /*
        if(rtcintflag) {
           rtcintflag=0;
           GetTimeStamp();
           printtime();
        }
         */
    }
}//end main
// ======================================================================

bool USER_USB_CALLBACK_EVENT_HANDLER(USB_EVENT event, void *pdata, uint16_t size)
{
    switch((int)event)
    {
        case EVENT_TRANSFER:
            break;

        case EVENT_SOF:
            /* We are using the SOF as a timer to time the LED indicator.  Call
            break;*/

        case EVENT_SUSPEND:
            break;

        case EVENT_RESUME:
            break;

        case EVENT_CONFIGURED:
            /* When the device is configured, we can (re)initialize the demo
             * code. */
            APP_DeviceCustomHIDInitialize();
            break;

        case EVENT_SET_DESCRIPTOR:
            break;

        case EVENT_EP0_REQUEST:
            /* We have received a non-standard USB request.  The HID driver
             * needs to check to see if the request was for it. */
            USBCheckHIDRequest();
            break;

        case EVENT_BUS_ERROR:
            break;

        case EVENT_TRANSFER_TERMINATED:
            break;

        default:
            break;
    }
    return true;
}

/*******************************************************************************
 End of File
*/

